﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Macro
{
    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct tagINPUT
    {
        /// DWORD->unsigned int
        public uint type;

        /// Anonymous_dccf47da_5155_438b_92bc_41adbefe840c
        public Anonymous_dccf47da_5155_438b_92bc_41adbefe840c Union1;
    }

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
    public struct Anonymous_dccf47da_5155_438b_92bc_41adbefe840c
    {
        /// MOUSEINPUT->tagMOUSEINPUT
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public tagMOUSEINPUT mi;

        /// KEYBDINPUT->tagKEYBDINPUT
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public tagKEYBDINPUT ki;

        /// HARDWAREINPUT->tagHARDWAREINPUT
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public tagHARDWAREINPUT hi;
    }

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct tagMOUSEINPUT
    {
        /// LONG->int
        public int dx;

        /// LONG->int
        public int dy;

        /// DWORD->unsigned int
        public uint mouseData;

        /// DWORD->unsigned int
        public uint dwFlags;

        /// DWORD->unsigned int
        public uint time;

        /// ULONG_PTR->unsigned int
        public uint dwExtraInfo;
    }

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct tagKEYBDINPUT
    {
        /// WORD->unsigned short
        public ushort wVk;

        /// WORD->unsigned short
        public ushort wScan;

        /// DWORD->unsigned int
        public uint dwFlags;

        /// DWORD->unsigned int
        public uint time;

        /// ULONG_PTR->unsigned int
        public uint dwExtraInfo;
    }

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct tagHARDWAREINPUT
    {
        /// DWORD->unsigned int
        public uint uMsg;

        /// WORD->unsigned short
        public ushort wParamL;

        /// WORD->unsigned short
        public ushort wParamH;
    }

    public partial class NativeMethods
    {
        /// Return Type: UINT->unsigned int
        ///cInputs: UINT->unsigned int
        ///pInputs: LPINPUT->tagINPUT*
        ///cbSize: int
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SendInput")]
        public static extern uint SendInput(uint cInputs, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct, SizeParamIndex = 0)] tagINPUT[] pInputs, int cbSize);
    }

    abstract class Command
    {
        protected double waitingTime;
        protected tagINPUT[] input;
        protected string description;

        public void execute()
        {
            if (NativeMethods.SendInput(1, input, 28) == 0)
            {
                Console.WriteLine("SendInput failed with code: " + Marshal.GetLastWin32Error().ToString());
            }
        }
        public string getDescription()
        {
            return description;
        }
        public double getWaitingTime()
        {
            return waitingTime;
        }
    }

    class keyboardCommand : Command
    {
        public keyboardCommand(double wt, ushort vkCode, bool keyDown, bool keyUp)
        {
            waitingTime = wt;

            input = new tagINPUT[1];
            description = "keyboard";

            const int INPUT_KEYBOARD = 1;
            input[0].type = INPUT_KEYBOARD;
            input[0].Union1.ki.wVk = vkCode;
            input[0].Union1.ki.wScan = 0;
            description += "  " + vkCode.ToString();

            uint flag = 0x0000;
            if (keyDown)
            {
                flag = (flag == 0x0000) ? 0x0000 : (flag | 0x0000);
                description += "  keyDown";
            }
            if (keyUp)
            {
                flag = (flag == 0x0000) ? 0x0002 : (flag | 0x0002);
                description += "  keyUp";
            }

            input[0].Union1.ki.dwFlags = flag;
        }
    }

    class mouseCommand : Command
    {
        public mouseCommand(double wt, int x, int y, bool lbuttonDown, bool lbuttonUp, bool rbuttonDown, bool rbuttonUp, bool mouseMove)
        {
            waitingTime = wt;

            input = new tagINPUT[1];
            description = "mouse";

            const int INPUT_MOUSE = 0;
            input[0].type = INPUT_MOUSE;
            input[0].Union1.mi.dx = x;
            input[0].Union1.mi.dy = y;
            input[0].Union1.mi.mouseData = 0;
            description += "  (" + x.ToString() + ", " + y.ToString() + ")";

            uint flag = 0x0000;
            if (lbuttonDown)
            {
                flag = (flag == 0x0000) ? 0x0002 : (flag |= 0x0002);
                description += "  lbuttonDown";
            }
            if (lbuttonUp)
            {
                flag = (flag == 0x0000) ? 0x0004 : (flag |= 0x0004);
                description += "  lbuttonUp";
            }
            if (rbuttonDown)
            {
                flag = (flag == 0x0000) ? 0x0008 : (flag |= 0x0008);
                description += "  rbuttonDown";
            }
            if (rbuttonUp)
            {
                flag = (flag == 0x0000) ? 0x0010 : (flag |= 0x0010);
                description += "  rbuttonUp";
            }
            if (mouseMove)
            {
                flag = (flag == 0x0000) ? (0x0001 | 0x8000) : (flag |= (0x0001 | 0x8000));
                description += "  move";
            }

            input[0].Union1.mi.dwFlags = flag;
        }
    }
}
